package com.ibm.risk.irmp.common.utils;

import jakarta.persistence.criteria.Predicate;
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
import org.springframework.data.jpa.domain.Specification;

import java.util.ArrayList;
import java.util.List;

public class SpringDataJpaUtils {
    /**
     * 实现日期范围查询
     * @param propName 字段名称
     * @param from 最小值
     * @param to 最大日期
     * @param inclusive 是否包含from和to
     * @param example 查询Example
     * @return Specification
     * @param <T> 要查询的实体类型
     * @param <E> 字段类型
     */
    public static <T, E extends Comparable<E>> Specification<T> getSpecDateFromToAndExample(String propName,
                                                                   E from, E to, boolean inclusive, Example<T> example) {
        ScopeCriteria<E> scopeCriteria = new ScopeCriteria<>(propName, from, to, inclusive, inclusive);
        return getSpecDateFromToAndExample(scopeCriteria, example);
    }

    /**
     * 实现日期范围查询
     *
     * @param <T>              要查询的实体类型
     * @param scopeCriteria     要查询的参数值范围
     * @param example          查询Example
     * @return Specification
     */
    public static <T, E extends Comparable<E>> Specification<T> getSpecDateFromToAndExample(ScopeCriteria<E> scopeCriteria, Example<T> example) {

        return (Specification<T>) (root, query, builder) -> {
            final List<Predicate> predicates = new ArrayList<>();

            if (scopeCriteria.from() != null) {
                if (scopeCriteria.includeFrom()) {
                    predicates.add(builder.greaterThanOrEqualTo(root.get(scopeCriteria.propName()), scopeCriteria.from()));
                } else {
                    predicates.add(builder.greaterThan(root.get(scopeCriteria.propName()), scopeCriteria.from()));
                }
            }
            if (scopeCriteria.to() != null) {
                if (scopeCriteria.includeTo()) {
                    predicates.add(builder.lessThanOrEqualTo(root.get(scopeCriteria.propName()), scopeCriteria.to()));
                } else {
                    predicates.add(builder.lessThan(root.get(scopeCriteria.propName()), scopeCriteria.to()));
                }
            }
            Predicate predicate = QueryByExamplePredicateBuilder.getPredicate(root, builder, example);
            if (predicate != null) {
                predicates.add(predicate);
            }
            return builder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
    };

}
